package com.example.criminalintent.activity;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.UUID;

import com.example.criminalintent.R;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;

public class CrimeCameraFragment extends Fragment {
	private static final String TAG = "CrimeCameraFragment";
	protected static final String EXTRA_PHOTO_FILENAME = "photo_file_name";
	
	private Camera mCamera;
	private SurfaceView mSurfaceView;
	// controls
	private Button btnTakePicture;
	private View mProgressBarContainer;
	private ProgressBar mProgressBar;
	
	// implements Camera.ShutterCallback to make mProgressContainer visible
	private Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback() {
		@Override
		public void onShutter() {
			// Display the progress indicator
			mProgressBarContainer.setVisibility(View.VISIBLE);
		}
	};
	
	// implements Camera.PictureCallback to handle naming and saving the JPEG file
	private Camera.PictureCallback mJpegCallback = new Camera.PictureCallback() {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			// Create a filename
			String fileName = UUID.randomUUID().toString() + ".jpg";
			// Save the jpeg data to disk
			FileOutputStream os = null;
			boolean success = true;
			try {
				os = getActivity().openFileOutput(fileName, Context.MODE_PRIVATE);
				os.write(data);
			} catch (FileNotFoundException e) {
				Log.e(TAG, "File not found");
				success = false;
			} catch (IOException e) {
				Log.e(TAG, "Error writing file: ", e);
				success = false;
			} finally {
				if (os != null) {
					try {
						os.close();
					} catch (IOException e) {
						Log.e(TAG, "Error closing file: ", e);
					}
				}
			}
			
			// Set the photo filename on the result intent
			if (success) {
				Log.i(TAG, "JPEG saved at " + fileName);
				Intent i = new Intent();
				i.putExtra(EXTRA_PHOTO_FILENAME, fileName);
				getActivity().setResult(Activity.RESULT_OK, i);
			} else {
				getActivity().setResult(Activity.RESULT_CANCELED);
			}
			getActivity().finish();
		}
	};
	
	@SuppressWarnings("deprecation")
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View v = inflater.inflate(R.layout.fragment_crime_camera, container, false);
		
		initControls(v);
		
		btnTakePicture.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View arg0) {
				if (null != mCamera) {
					mCamera.takePicture(mShutterCallback, null, mJpegCallback);
				}
			}
		});
		
		// Start using Camera API
		final SurfaceHolder holder = mSurfaceView.getHolder();
		// setType() and SURFACE_TYPE_PUSH_BUFFERS are both deprecated,
		// but are required for Camera preview to work on pre-3.0 devices.
		holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		// listens for events in the lifecycle of a Surface so that you can
		// coordinate the Surface with its client.
		holder.addCallback(new Callback() {
			@Override
			public void surfaceCreated(SurfaceHolder arg0) {
				// Tell the camera to use this surface as its preview area
				try {
					if (null != mCamera) {
						mCamera.setPreviewDisplay(holder);
					}
				} catch (IOException e) {
					Log.e(TAG, "Error setting up preview display", e);
				}
			}
			
			@Override
			public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
				if (null == mCamera) {
					return;
				}
				// The surface has changed size; update the camera preview size
				Camera.Parameters params = mCamera.getParameters();
				Size s = getBestSupportedSize(params.getSupportedPreviewSizes(), width, height);
				params.setPreviewSize(s.width, s.height);
				// Set the picture size for camera
				s = getBestSupportedSize(params.getSupportedPictureSizes(), width, height);
				params.setPictureSize(s.width, s.height);
				
				mCamera.setParameters(params);
				try {
					mCamera.startPreview();
				} catch (Exception e) {
					Log.e(TAG, "Could not start preview", e);
					mCamera.release();
					mCamera = null;
				}
			}
			
			@Override
			public void surfaceDestroyed(SurfaceHolder arg0) {
				// We can no longer display on this surface, so stop the preview.
				if (null != mCamera) {
					mCamera.stopPreview();
				}
			}
		});
		
		return v;
	}

	private void initControls(View v) {
		btnTakePicture = (Button) v.findViewById(R.id.btnTakePicture);
		mSurfaceView = (SurfaceView) v.findViewById(R.id.crime_camera_surfaceView);
		mProgressBarContainer = v.findViewById(R.id.crime_camera_progressContainter);
		mProgressBarContainer.setVisibility(View.INVISIBLE);
	}
	
	private Size getBestSupportedSize(List<Size> sizes, int width, int height) {
		Size bestSize = sizes.get(0);
		int largestArea = bestSize.width * bestSize.height;
		for (Size item : sizes) {
			int area = item.width * item.height;
			if (area > largestArea) {
				bestSize = item; 
				largestArea = area;
			}
		}
		return bestSize;
	}

	@Override
	public void onResume() {
		super.onResume();
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
			mCamera = Camera.open(0);
		} else {
			mCamera = Camera.open();
		}
	}

	@Override
	public void onPause() {
		super.onPause();
		if (null != mCamera) {
			mCamera.release();
			mCamera = null;
		}
	}
	
}
